/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkFlvFileSource.h"
#include "MkEvent/MkTimer.h"


CMkFlvFileSource::CMkFlvFileSource(FILE *fp, CMkTimer* pTimer)
    : CMkFileSource(MkMediaSourceFileFlv, fp, pTimer)
{

}

Uint32 CMkFlvFileSource::ScanFile()
{
    CMkFlvDemuxer FlvDemuxer;
    Uint32 nTotalOffset = 0;
    Uint32 ErrorCode = NoneError;
    while (TRUE) {
        Uint32 nToRead = m_MaxLen - m_nOffset;
        int nRead = fread(m_pBuf + m_nOffset, 1, nToRead, m_pFp);
        if (nRead <= 0) {
            break;
        }
        m_nOffset += nRead;
        Uint32 nUsed = 0;
        ErrorCode = FlvDemuxer.InputData(m_pBuf, m_nOffset, nUsed);
        MkEsPacket EsPacket;
        while (TRUE) {
            ErrorCode = FlvDemuxer.GetEsPacket(EsPacket);
            if (NoneError != ErrorCode) {
                break;
            }
            MkFilePacketParam Param;
            Param.bKeyFrame = EsPacket.bKeyPacket;
            Param.CodecType = EsPacket.CodecType;
            //Param.Dts = EsPacket.Dts;
            //Param.Pts = EsPacket.Pts;
            MkListBuffer::const_iterator it = EsPacket.BufferList.GetBufferList().begin();
            for (; it != EsPacket.BufferList.GetBufferList().end(); it++) {
                Param.VecPacket.push_back(std::pair<Uint32, Uint32>((const Uint8*)it->GetBuffer() - m_pBuf + nTotalOffset, it->GetLength()));
            }
            m_VecPacket.emplace_back(Param);
        }
        nTotalOffset += nUsed;
        memmove(m_pBuf, m_pBuf + nUsed, m_nOffset - nUsed);
        m_nOffset -= nUsed;
    }
    SetVideoParam(FlvDemuxer.GetVideoParam());
    SetAudioParam(FlvDemuxer.GetAudioParam());
    return NoneError;
}

Uint32 CMkFlvFileSource::GetNextFrame(MkVector<MkEsPacket>& VecEsPacket)
{
    if (m_ReadFrameIndex >= m_VecPacket.size()) {
        if (m_pTimer) {
            m_pTimer->DeleteTimer(m_FrameGetTimer);
        }

        MkEsPacket EsPacket;
        EsPacket.Pts = EsPacket.Dts = m_Pts;
        EsPacket.bKeyPacket = TRUE;
        EsPacket.CodecType = GetVideoParam().GetCodec();
        VecEsPacket.emplace_back(EsPacket);
    } else {
        //has video
        if (MkCodecUnknown != GetVideoParam().GetCodec()) {
            BOOL bGetVideo = FALSE;
            while (m_ReadFrameIndex < m_VecPacket.size()) {
                MkEsPacket EsPacket;
                EsPacket.Pts = EsPacket.Dts = m_Pts;
                MkFilePacketParam ReadPacketParam = m_VecPacket[m_ReadFrameIndex];
                if (MkCodecCavs > ReadPacketParam.CodecType) {
                    if (bGetVideo) {
                        break;
                    }
                    m_Pts += static_cast<Uint32>(1000 / (GetVideoParam().GetFrameRate()*GetSpeed()));
                    bGetVideo = TRUE;
                }
                m_ReadFrameIndex++;
                if (GetSpeed() >= 8.0 && !ReadPacketParam.bKeyFrame) {
                    return NoneError;
                }
                EsPacket.bKeyPacket = ReadPacketParam.bKeyFrame;
                EsPacket.CodecType = ReadPacketParam.CodecType;
                if (EsPacket.bKeyPacket
                    && MkCodecCavs >= EsPacket.CodecType
                    && ReadPacketParam.VecPacket.size() < 3) {
                    if (!GetVideoParam().GetVps().empty()) {
                        EsPacket.BufferList.Append(GetVideoParam().GetVps().c_str(), GetVideoParam().GetVps().size());
                    }
                    if (!GetVideoParam().GetSps().empty()) {
                        EsPacket.BufferList.Append(GetVideoParam().GetSps().c_str(), GetVideoParam().GetSps().size());
                    }
                    if (!GetVideoParam().GetPps().empty()) {
                        EsPacket.BufferList.Append(GetVideoParam().GetPps().c_str(), GetVideoParam().GetPps().size());
                    }
                }
                Uint32 nOffset = 0;
                Uint8 NaluType = 0;
                for (size_t i = 0; i < ReadPacketParam.VecPacket.size(); i++) {
                    fseek(m_pFp, ReadPacketParam.VecPacket[i].first, SEEK_SET);
                    fread(m_pBuf + nOffset, 1, ReadPacketParam.VecPacket[i].second, m_pFp);
                    EsPacket.BufferList.Append(m_pBuf + nOffset, ReadPacketParam.VecPacket[i].second);
                    nOffset += ReadPacketParam.VecPacket[i].second;
                }

                VecEsPacket.emplace_back(EsPacket);
            }
        } else if (MkCodecUnknown != GetAudioParam().GetCodec()) {
            MkEsPacket EsPacket;
            EsPacket.Pts = EsPacket.Dts = m_Pts;
            MkFilePacketParam ReadPacketParam = m_VecPacket[m_ReadFrameIndex];
            m_ReadFrameIndex++;
            m_Pts += static_cast<Uint32>(1000 * 1000 / (CMkMediaUtil::AudioSampleRateIndexToRate(GetAudioParam().GetSampleRate())*GetSpeed()));
            EsPacket.bKeyPacket = TRUE;
            EsPacket.CodecType = ReadPacketParam.CodecType;
            Uint32 nOffset = 0;
            Uint8 NaluType = 0;
            for (size_t i = 0; i < ReadPacketParam.VecPacket.size(); i++) {
                fseek(m_pFp, ReadPacketParam.VecPacket[i].first, SEEK_SET);
                fread(m_pBuf + nOffset, 1, ReadPacketParam.VecPacket[i].second, m_pFp);
                EsPacket.BufferList.Append(m_pBuf + nOffset, ReadPacketParam.VecPacket[i].second);
                nOffset += ReadPacketParam.VecPacket[i].second;
            }
            VecEsPacket.emplace_back(EsPacket);
        }
    }
    return NoneError;
}

CMkFlvFileSource::~CMkFlvFileSource()
{

}